#ifndef EXEC_H
#define EXEC_H
#include "ccas/ccas.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

// 运行子进程的最大容量
#define MAX_SIZE 64 
// PID字段转换为10进制字符串的最大长度
#define MAX_PID_STRLEN 16

struct Task {
	pid_t pid;
	char *path;
};

/* 子进程池
 *
 */
//static pid_t ps[MAX_SIZE] = {0};
static struct Task tasks[MAX_SIZE];
/* 初始化任务池（进程池） */
void ps_init() {
	for (int i=0; i<MAX_SIZE; ++i) {
		tasks[i].pid =0 ;
		tasks[i].path=NULL;
	}
}

/* 释放全部的进程标签，*/
void ps_free() {
	for (int i=0; i<MAX_SIZE; ++i) {
		if (tasks[i].path != NULL) {
			free(tasks[i].path);
		}
	}
}
/* 子进程池是否满了
 *
 */
static int is_full() {
	for (int i=0; i<MAX_SIZE; ++i) {
		if (tasks[i].pid == 0)
			return 0;
	}
	return 1;
}

/* 检查该进程ID是否存在于子进程池中
 *
 */
static int p_in(pid_t pid) {
	for (int i=0; i<MAX_SIZE; ++i) {
		if (tasks[i].pid == pid)
			return 1;
	}
	return 0;
}

/* 保存子进程
 *
 */
static void save_pid(pid_t pid, char *path) {
	for (int i =0; i<MAX_SIZE; ++i) {
		if (tasks[i].pid == 0) {
			tasks[i].pid =pid;
			tasks[i].path = path;
			return;
		}
	}
}

/* 列出所有的进程pid和进程名 */
char *p_list() {
	string M = NULL;
	char pid[MAX_PID_STRLEN];
	for (int i=0; i<MAX_SIZE; ++i) {
		if (tasks[i].pid > 0) {
			/* 清空存放pid的数组 */
			for (int j=0; j<MAX_PID_STRLEN; ++j) {
				pid[j] = '\0';
			}
			// 输出pid到数组
			snprintf(pid, MAX_PID_STRLEN , "%zu", tasks[i].pid); // 写入协议头
			ccas_as(&M, pid);
			ccas_as(&M, " ");
			ccas_as(&M, tasks[i].path);
			ccas_as(&M, "\n");
		}
	}
	char *ls = ccas_ws(M);
	ccas_free(&M);
	return ls;
}

/* 运行一个命令，这个函数由子进程使用
 *
 */
static int p_start(char *path) {
	char *args[] = {path, NULL};
	execvp(path, args);
	perror("execvp failed");
	return 1;
}

/* 创建一个子进程，该函数由父进程使用
 *
 */
int crt_p(char *path) {
	if (is_full()) return 1; // 进程池已满
	pid_t pid = fork();
	if (pid < 0) { // fork失败
		perror("fork failed");
		return 1;
	} else if (pid == 0) { // 子进程执行区
		p_start(path);
	} else { // 父进程区
		if (!p_in(pid)) { // 和之前的子进程编号一样
		       save_pid(pid, path);
		}
		return 0;
	}
}

/*等待子进程退出
 *
 */
void wait_p() {
	wait(NULL);
}

#endif
